using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Text;
using Tsanie.ShellExtension.Shell;

namespace Tsanie.ShellExtension.Shell {

    [Guid("FB2EC55F-FB7B-432a-A54E-EDB524B951A6")]
    public class ShellView : IShellView {

        #region - Fields -

        internal ShellFolder m_mc = null;
        internal Form m_form = null;
        public IShellBrowser m_shell = null;
        internal FOLDERSETTINGS m_folderSettings = new FOLDERSETTINGS();
        private IntPtr m_hhook = IntPtr.Zero;
        private HookStuff.HookProc h = null;
        private bool m_fired = false;

        #endregion

        public ShellView(ShellFolder m) {
            this.m_mc = m;
            this.h = new HookStuff.HookProc(this.OnDialogMsg);
        }

        #region - IShellView Members -

        void IShellView.GetWindow(out IntPtr phwnd) { phwnd = this.m_form.Handle; }
        void IShellView.ContextSensitiveHelp(bool fEnterMode) { }
        long IShellView.TranslateAcceleratorA(IntPtr pmsg) { return 1; }
        void IShellView.EnableModeless(bool fEnable) { }
        void IShellView.UIActivate(uint uState) {
            if (uState == 0) //destroy
                this.m_form.Close();
        }
        void IShellView.Refresh() { }

        #endregion

        #region - Private Methods -

        private long OnDialogMsg(int nCode, uint wParam, int lParam) {
            IntPtr p = new IntPtr(lParam);
            CWPRETSTRUCT m = (CWPRETSTRUCT)Marshal.PtrToStructure(p, typeof(CWPRETSTRUCT));
            bool handled = false;
            if (m.message == 0x004E && handled == false) { //WM_NOTIFY
                NMHDR n = (NMHDR)Marshal.PtrToStructure(new IntPtr(m.lParam), typeof(NMHDR));
                if (n.code == 0xFFFFFDA2) { // the special common dialog notifier
                    handled = true;
                    if (this.m_mc.OnAction != null) {
                        if (!m_fired) {
                            this.m_mc.OnAction(this.GetActionType());
                            m_fired = true;
                        }
                    }
                }

            }
            if (m.message == 0x00F3 && handled == false) { // BN_SETSTATE
                if (m.wParam != 0) {
                    int id = HookStuff.GetDlgCtrlID(m.hwnd);
                    if (id == 1) {
                        handled = true;
                        if (this.m_mc.OnAction != null) {
                            if (!m_fired) {
                                this.m_mc.OnAction(this.GetActionType());
                                m_fired = true;
                            }
                        }
                    }
                }
            }
            uint specialCode = HookStuff.RegisterWindowMessage("WM_OBJECTSEL");
            if (m.message == specialCode && m.lParam == 0x25 && handled == false) { //WM_OBJECTSEL
                handled = true;
                if (this.m_mc.OnAction != null) {
                    this.m_mc.OnAction(this.GetActionType());
                    m_fired = true;
                }
            }
            return HookStuff.CallNextHookEx(this.m_hhook, nCode, wParam, lParam);
        }

        private ShellActionType GetActionType() {
            string text = this.m_mc.ParentWindowText;
            if (text.ToLower().IndexOf("open") != -1)
                return ShellActionType.Open;
            if (text.ToLower().IndexOf("save") != -1)
                return ShellActionType.Save;
            return ShellActionType.Unknown;
        }

        #endregion

        #region - IShellView Members -

        void IShellView.CreateViewWindow(IntPtr psvPrevious, ref FOLDERSETTINGS pfs, IShellBrowser psb, ref RECT prcView, ref IntPtr phWnd) {
            this.m_folderSettings.ViewMode = pfs.ViewMode;
            this.m_folderSettings.fFlags = pfs.fFlags;
            this.m_form = this.m_mc.m_form;
            IntPtr hwnd = IntPtr.Zero;
            this.m_shell = psb;
            this.m_shell.GetWindow(out hwnd);
            ShellFolder.SetParent(m_form.Handle, hwnd);
            phWnd = m_form.Handle;
            int w = prcView.right - prcView.left;
            int h = prcView.bottom - prcView.top;
            ShellFolder.SetWindowLong(m_form.Handle, -16, 0x40000000);
            ShellFolder.SetWindowPos(m_form.Handle, 0, 0, 0, w, h, 0x0017);
            m_form.Location = new System.Drawing.Point(prcView.left, prcView.top);
            m_form.Size = new System.Drawing.Size(prcView.right - prcView.left, prcView.bottom - prcView.top);
            m_form.Show();
            HookStuff.SetFocus(hwnd);
            //			CWPRETSTRUCT
            this.m_hhook = HookStuff.SetWindowsHookEx(12, this.h, IntPtr.Zero, HookStuff.GetCurrentThreadId());
        }
        void IShellView.DestroyViewWindow() {
            this.m_form.Close();
            bool b = HookStuff.UnhookWindowsHookEx(this.m_hhook);
        }
        void IShellView.GetCurrentInfo(ref FOLDERSETTINGS pfs) {
            pfs = this.m_folderSettings;
        }
        void IShellView.AddPropertySheetPages(long dwReserved, ref IntPtr pfnPtr, int lparam) {
            pfnPtr = IntPtr.Zero;
        }
        void IShellView.SaveViewState() { }
        void IShellView.SelectItem(IntPtr pidlItem, uint uFlags) { }
        long IShellView.GetItemObject(uint uItem, ref Guid riid, ref IntPtr ppv) {
            Common.OutputDebugString("GetItemObject():: uItem: {0}, riid: {1}, ppv: {2}", uItem, riid, ppv);
            ppv = IntPtr.Zero;
            if (riid == typeof(MMC.IDataObject).GUID && (uItem == 1 || uItem == 2)) {
                if (uItem == 1)
                    this.m_mc.m_mdo = new MMC.MyDataObject(255, this.m_mc.m_pidlData);
                if (uItem == 2)
                    this.m_mc.m_mdo = new MMC.MyDataObject(0, this.m_mc.m_pidlData);
                ppv = Marshal.GetComInterfaceForObject(this.m_mc.m_mdo, typeof(MMC.IDataObject));
                return 0;
            }
            Marshal.QueryInterface(Marshal.GetIUnknownForObject(this), ref riid, out ppv);
            if (ppv.ToInt32() == 0)
                Marshal.QueryInterface(Marshal.GetIUnknownForObject(this.m_mc), ref riid, out ppv);
            if (ppv.ToInt32() == 0)
                return 0x80004002L;
            return 0;
        }

        #endregion

    }
}
